﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;

namespace DevelopTool.Common.ILSpy
{
    /// <summary>
    /// ILSpy帮助类
    /// </summary>
    public class ILSpyHelper
    {
        /// <summary>
        /// 全局状态，用于控制反编译过程中是否继续
        /// </summary>
        public bool Status { get; set; } = true;

        /// <summary>
        ///等待超时的分钟数，单位：分钟，默认5分钟
        /// </summary>
        public int WaitTimeOut { get; set; } = 5;


        private readonly CSharpLanguage csharpLanguage;


        public ILSpyHelper()
        {
            this.csharpLanguage = new CSharpLanguage();
        }



        /// <summary>
        /// 获取程序集反编译的内容
        /// </summary>
        /// <param name="assemblyPath"></param>
        /// <returns></returns>
        public string GetAssemblyContent(string assemblyPath)
        {
            List<Tuple<string,string>> list = new List<Tuple<string,string>>();
            try
            {

                AssemblyList asmlist = new AssemblyList("mylistname");
                LoadedAssembly loadedAssembly = asmlist.OpenAssembly(assemblyPath,false);
                DecompilationOptions options = GetDecompilationOptions(asmlist);
                options.assenmlyList = asmlist;

                var textOutput = new PlainTextOutput();
                this.csharpLanguage.DecompileAssembly(loadedAssembly,textOutput,options);//反编译程序集

                return textOutput.ToString();
            }
            catch(Exception)
            {
                return string.Empty;
            }
        }


        /// <summary>
        /// 获取程序集内的所有类文本
        /// </summary>
        /// <param name="assemblyPath">程序集路径</param>
        /// <param name="waitTimeOut">反编译等待时间，默认5分钟</param>
        /// <returns>包含反编译结果的列表，每个元素是一个元组，包含类的完全限定名和反编译后的代码。</returns>
        public List<Tuple<string,string>> GetClassListByAssembly(string assemblyPath)
        {
            List<Tuple<string,string>> list = new List<Tuple<string,string>>();

            try
            {
                AssemblyList asmlist = new AssemblyList("mylistname");
                LoadedAssembly loadedAssembly = asmlist.OpenAssembly(assemblyPath,false);

                ModuleDefinition moduleDefinition = loadedAssembly.ModuleDefinition;
                if(moduleDefinition == null) return list;

                DecompilationOptions options = GetDecompilationOptions(asmlist);

                foreach(TypeDefinition type in moduleDefinition.Types)
                {
                    if(Status == false) break;//反编译过程中每次判断下状态，防止占用过多的时间

                    Task.Factory.StartNew(() =>
                    {
                        try
                        {
                            using(StringWriter output = new StringWriter())
                            {
                                csharpLanguage.DecompileType(type,new PlainTextOutput(output),options);
                                if(output != null)
                                {
                                    string classText = output.ToString();
                                    if(!string.IsNullOrEmpty(classText))
                                    {
                                        list.Add(new Tuple<string,string>(type.FullName,classText));
                                    }
                                }
                            }
                        }
                        catch
                        { }
                    }).Wait(TimeSpan.FromMinutes(WaitTimeOut));//等待超时
                }

                return list;
            }
            catch(Exception)
            {
                return list;
            }
        }

        /// <summary>
        /// 获取类数量
        /// </summary>
        /// <param name="assemblyPath"></param>
        /// <returns></returns>
        public int GetTypesCount(string assemblyPath)
        {
            try
            {
                AssemblyList asmlist = new AssemblyList("mylistname");
                LoadedAssembly loadedAssembly = asmlist.OpenAssembly(assemblyPath,false);

                var moduleDefinition = loadedAssembly.ModuleDefinition;
                if(moduleDefinition == null) return 0;
                if(moduleDefinition.Types == null) return 0;
                return moduleDefinition.Types.Count;
            }
            catch(Exception)
            {
                return 0;
            }
        }


        private DecompilationOptions GetDecompilationOptions(AssemblyList asmlist = null)
        {
            var decompilationOptions = new DecompilationOptions
            {
                FullDecompilation = true,//是否完全反编译程序集（递归所有成员）

                DecompilerSettings = GetDecompilerSettings(),

                // SaveAsProjectDirectory = "", //保存（输出）项目的目录。
                //  assenmlyList = asmlist,
                //IncludedClassName = "haha"
            };
            return decompilationOptions;
        }


        /// <summary>
        /// 获取反编译设置
        /// </summary>
        /// <returns></returns>
        private DecompilerSettings GetDecompilerSettings()
        {
            return new DecompilerSettings
            {
                AnonymousMethods = true,  // 控制是否将匿名方法以Lambda表达式的形式输出
                AsyncAwait = true,  // 控制是否将异步方法反编译为使用async和await
                AutomaticProperties = true,  // 控制是否将自动实现的属性合并为简单属性声明
                AutomaticEvents = true,  // 控制是否将自动实现的事件合并为简单事件声明
                ExpressionTrees = true,  // 控制是否使用表达式树进行反编译
                YieldReturn = true,  // 控制是否使用yield return或yield break进行迭代器方法的反编译
                ShowXmlDocumentation = true,  // 显示XML文档
                UsingDeclarations = true,  // 控制是否使用using声明
                FullyQualifyAmbiguousTypeNames = true,  // 控制是否在存在类型歧义时使用完全限定名
                UseDebugSymbols = true,  // 控制是否考虑调试符号来使输出的代码更具可读性
                ObjectOrCollectionInitializers = true,  // 控制是否使用对象或集合初始化器
                IntroduceIncrementAndDecrement = true,  // 控制是否引入++和--
                MakeAssignmentExpressions = true,  // 控制是否将赋值语句转换为表达式
                FoldBraces = true,  // 控制是否在可能的情况下省略大括号
                AlwaysGenerateExceptionVariableForCatchBlocks = true,  // 控制是否总是为catch块生成异常变量
                UsingStatement = true,  // 控制using定义
                ForEachStatement = true,  // 控制foreach语句
                LockStatement = true, // 控制锁lock语句
                SwitchStatementOnString = true,  // 控制Switch的条件
                QueryExpressions = true,  // 控制查询表达式

                CSharpFormattingOptions = FormattingOptionsFactory.CreateEmpty()//代码格式
            };
        }
    }

}
